package com.sloera.thread;

/**
 * @author sloera
 * @create 2020/5/2
 */

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 题目：多线程之间按顺序调用，实现A->B->C三个线程启动，要求如下：
 * AA打印5次，BB打印10次，CC打印15次
 * 重复10次
 */
public class SyncAndReentrantLockDemo {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareResource.choose(1);
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareResource.choose(2);
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareResource.choose(3);
            }
        }, "C").start();
    }
}

class ShareResource {
    //对应当前应执行的线程
    private int number = 1; // A:1 B:2 C:3
    private Lock lock = new ReentrantLock();
    //对应三个线程条件
    private Condition ca = lock.newCondition();
    private Condition cb = lock.newCondition();
    private Condition cc = lock.newCondition();

    /**
     * 选择执行哪个线程的方法，并通知下一线程
     * 由于三个线程执行方法具有相似性，所以封装起来选择
     *
     * @param thread 对应线程A:1 B:2 C:3
     */
    public void choose(int thread) {
        lock.lock();
        try {
            // 线程对应的条件
            List<Condition> cList = new ArrayList<>();
            cList.add(ca);
            cList.add(cb);
            cList.add(cc);
            // 是否应该执行传入的thread线程方法
            while (number != thread) {
                cList.get(thread - 1).await();
            }
            //TODO 枚举。 线程对应执行方法的次数
            switch (thread) {
                case 1:
                    print(5);
                    break;
                case 2:
                    print(10);
                    break;
                case 3:
                    print(15);
                    break;
                default:
            }
            //依次循环通知
            number++;
            if (number == 4) {
                number = 1;
            }
            cList.get(number - 1).signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 每次调用方法的实际工作
     */
    public void print(int time) {
        //for (int i = 0; i < time; i++) {
        //    System.out.println(Thread.currentThread().getName() + "\t" + (i+1));
        //}
        System.out.println(Thread.currentThread().getName() + "\t" + time);
    }
}
